package visit

import (
	"path/filepath"
	"regexp"
	"strings"
)

type visitOption struct {
	IncludeExt []string // 包含的扩展名
	ExcludeExt []string // 排除的扩展名
	NameReg    string   // 文件名正则表达式

	joinIncludeExt   string
	joinExcludeExt   string
	verifyIncludeExt bool
	verifyExcludeExt bool

	nameReg *regexp.Regexp
}

func (o *visitOption) init() {
	if len(o.IncludeExt) > 0 {
		o.joinIncludeExt = "." + strings.Join(o.IncludeExt, ".")
		o.verifyIncludeExt = true
	}
	if len(o.ExcludeExt) > 0 {
		o.joinExcludeExt = "." + strings.Join(o.ExcludeExt, ".")
		o.verifyExcludeExt = true
	}
	if o.NameReg != "" {
		o.nameReg = regexp.MustCompile(o.NameReg)
	}
}

func (o *visitOption) filePathInRule(path string) bool {
	ext := filepath.Ext(path)
	ext = strings.ToLower(ext)
	if o.verifyIncludeExt && o.joinIncludeExt != "" && !strings.Contains(o.joinIncludeExt, ext) {
		return false
	}
	if o.verifyExcludeExt && o.joinExcludeExt != "" && strings.Contains(o.joinExcludeExt, ext) {
		return false
	}
	if o.nameReg != nil && !o.nameReg.MatchString(path) {
		return false
	}
	return true
}

func defaultOption() *visitOption {
	return &visitOption{
		IncludeExt: []string{},
		ExcludeExt: []string{},
		NameReg:    "",
	}
}

func mixOptions(opt *visitOption, opts ...Option) *visitOption {
	for _, o := range opts {
		o(opt)
	}
	opt.init()
	return opt
}

type Option func(*visitOption)

func WithIncludeExt(exts ...string) Option {
	return func(o *visitOption) {
		o.IncludeExt = append(o.IncludeExt, exts...)
	}
}

func WithExcludeExt(exts ...string) Option {
	return func(o *visitOption) {
		o.ExcludeExt = append(o.ExcludeExt, exts...)
	}
}

func WithNameReg(nameReg string) Option {
	return func(o *visitOption) {
		o.NameReg = nameReg
	}
}
